package com.itheima.service.impl;

import com.itheima.common.entity.Result;
import com.itheima.dto.BusinessReportDto;
import com.itheima.dto.HotSetmealDto;
import com.itheima.file.ExcelTemplate;
import com.itheima.pojo.MemberReport;
import com.itheima.pojo.SetmealReport;
import com.itheima.service.IMemberService;
import com.itheima.service.IOrderService;
import com.itheima.service.IReportService;
import com.itheima.service.ISetmealService;
import lombok.extern.slf4j.Slf4j;
import org.apache.xmlbeans.impl.jam.provider.ResourcePath;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class IReportServiceImpl implements IReportService {

    @Autowired
    private IMemberService memberService;

    @Autowired
    private ISetmealService setmealService;

    @Autowired
    private IOrderService orderService;


    /**
     * 获取会员数量统计数据
     *
     * @return
     */
    @Override
    public Result getMemberReport() {
        HashMap<String, Object> map = new HashMap<>();

        //构建最近十二月日期
        LocalDate now = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        List<String> dateList = new ArrayList<>();
        dateList.add(now.format(formatter));
        for (int i = 1; i <= 11; i++) {
            dateList.add(now.minusMonths(i).format(formatter));
        }
        Collections.reverse(dateList);

        System.out.println(dateList);
        map.put("months", dateList);

        //查询最近12个月的用户数量
        List<MemberReport> memberReportList = memberService.getMemberCountByDate(dateList);
        System.out.println(memberReportList);
        Map<String, Integer> memberCountMap = memberReportList.stream().collect(Collectors.toMap(MemberReport::getDates, MemberReport::getMemberCount));
        List<Integer> memberCountList = new ArrayList<>(dateList.size());
        for (String date : dateList) {
            Integer memberCount = memberCountMap.get(date);
            if (memberCount == null) {
                memberCountList.add(0);
            } else {
                memberCountList.add(memberCount);
            }
        }
        System.out.println(memberCountList);
        map.put("memberCount", memberCountList);


        return Result.of(true, "获取会员统计数据成功", map);
    }

    /**
     * 获取套餐占比统计数据
     *
     * @return
     */
    @Override
    public Result getSetmealReport() {
        Map<String, Object> map = new HashMap<>();
        List<SetmealReport> setmealReportList = setmealService.getSetmealReport();
        List<String> setmealNameList = new ArrayList<>(setmealReportList.size());
        for (SetmealReport setmealReport : setmealReportList) {
            setmealNameList.add(setmealReport.getName());
        }
        map.put("setmealNames", setmealNameList);
        map.put("setmealCount", setmealReportList);
        return Result.of(true, "获取套餐统计数据成功", map);
    }

    /**
     * 获取运营统计数据
     *
     * @return
     */
    @Override
    public Result getBusinessReportData() {
        LocalDate now = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        //生成报告日期
        String reportDate = now.format(formatter);
        //查询今日到诊人数
        Integer todayVisitsNumber = orderService.getTodayVisitsNumber(reportDate);
        //查询今天新增用户
        Integer todayNewMember = memberService.getTodayNewMember(reportDate);

        //查询本周到诊人数
        /*int dayOfWeek = now.getDayOfWeek().getValue();
        List<String> weekDate = new ArrayList<>(dayOfWeek);
        weekDate.add(reportDate);
        for (int i = 1; i < dayOfWeek; i++) {
            weekDate.add(now.minusDays(i).format(formatter));
        }*/

        // 使用周枚举分组计算得到当前日期对应周的7天日期
        List<LocalDate> weekDays = Arrays.stream(DayOfWeek.values()).map(now::with).collect(Collectors.toList());
        // 转换
        List<String> weekDate = weekDays.stream().map(LocalDate::toString).collect(Collectors.toList());
        System.out.println(weekDate);
        Integer thisWeekVisitsNumber = orderService.getVisitsNumberBydates(weekDate);
        //查询当月新增用户

        //获取当月最后一天
        int lastDayOfMonth = now.lengthOfMonth();
        //获取今天是当月的第几天
        int dayOfMonth = now.getDayOfMonth();
        //获取当月第一天
        LocalDate firstDayOfMonth = now.minusDays(dayOfMonth - 1);

        List<String> monthDate = new ArrayList<>(lastDayOfMonth);
        monthDate.add(firstDayOfMonth.format(formatter));
        for (int i = 1; i < lastDayOfMonth; i++) {
            monthDate.add(firstDayOfMonth.plusDays(i).format(formatter));
        }
        System.out.println(monthDate);
        Integer thisMonthNewMember = memberService.getNewMember(monthDate);
        //查询本周新增用户
        Integer thisWeekNewMember = memberService.getNewMember(weekDate);
        //获取总会员数
        Integer totalMember = memberService.getTotalMember();
        //获取本月预约数
        Integer thisMonthOrderNumber = orderService.getOrderNumberByDate(monthDate);
        //查询本月到诊人数
        Integer thisMonthVisitsNumber = orderService.getVisitsNumberBydates(monthDate);
        //查询今日预约数
        Integer todayOrderNumber = orderService.getTodayOrderNumber(reportDate);
        //查询本周预约数
        Integer thisWeekOrderNumber = orderService.getOrderNumberByDate(weekDate);
        //获取热门套餐数据
        List<HotSetmealDto> hotSetmealDtoList = setmealService.getHotSetmeals();
        //封装返回
        BusinessReportDto businessReportDto = new BusinessReportDto();
        businessReportDto.setReportDate(reportDate);
        businessReportDto.setHotSetmeal(hotSetmealDtoList);
        businessReportDto.setThisMonthNewMember(thisMonthNewMember);
        businessReportDto.setThisWeekNewMember(thisWeekNewMember);
        businessReportDto.setTodayNewMember(todayNewMember);
        businessReportDto.setThisMonthOrderNumber(thisMonthOrderNumber);
        businessReportDto.setThisWeekOrderNumber(thisWeekOrderNumber);
        businessReportDto.setTodayOrderNumber(todayOrderNumber);
        businessReportDto.setThisMonthVisitsNumber(thisMonthVisitsNumber);
        businessReportDto.setThisWeekVisitsNumber(thisWeekVisitsNumber);
        businessReportDto.setTodayVisitsNumber(todayVisitsNumber);
        businessReportDto.setTotalMember(totalMember);

        return Result.of(true, "获取运营统计数据成功", businessReportDto);
    }

    /**
     * 导出运营数据到Excel
     *
     * @param response
     */
    @Override
    public void exportBusinessReport(HttpServletResponse response) {

        // 加载导出模板，excel模板的项目中路径
        ExcelTemplate excel = new ExcelTemplate("/templates/report_template.xlsx");
        if (!excel.examine()) {
            log.error("模板不可用!");
            return;
        }

        // 使用一个Map来存储所有的行区域，
        // 每个行区域对应Map的一个键
        LinkedHashMap<Integer, LinkedList<String>> rows = new LinkedHashMap<>();
        // 创建第一个行区域里面填充的值，ExcelTemplate会按从左至右，
        // 从上往下的顺序，挨个填充区域里面的${}，所以创建的时候注意顺序就好

        //获取数据

        Result result = this.getBusinessReportData();
        BusinessReportDto businessReportDto = (BusinessReportDto) result.getData();

        //填充热门套餐数据
        List<HotSetmealDto> hotSetmealDtoList = businessReportDto.getHotSetmeal();
        for (int i = 0; i < hotSetmealDtoList.size(); i++) {
            HotSetmealDto hotSetmealDto = hotSetmealDtoList.get(i);
            LinkedList<String> row = new LinkedList<>();
            row.add(hotSetmealDto.getName());
            row.add(hotSetmealDto.getSetmeal_count().toString());
            row.add(hotSetmealDto.getProportion().toString());
            row.add("无");
            rows.put(i + 1, row);
        }
        // 创建需要填充替换的值
        //${参数名}
        Map<String, String> fill = new HashMap<>();
        //报告日期
        fill.put("reportDate", businessReportDto.getReportDate());
        //今日新增用户
        fill.put("todayNewMember", businessReportDto.getTodayNewMember().toString());
        //总用户
        fill.put("totalMember", businessReportDto.getTotalMember().toString());
        //本周新增用户
        fill.put("thisWeekNewMember", businessReportDto.getThisWeekNewMember().toString());
        //本月新增用户
        fill.put("thisMonthNewMember", businessReportDto.getThisMonthNewMember().toString());
        //今日预约人数
        fill.put("todayOrderNumber", businessReportDto.getTodayOrderNumber().toString());
        //本周预约人数
        fill.put("thisWeekOrderNumber", businessReportDto.getThisWeekOrderNumber().toString());
        //本月预约人数
        fill.put("thisMonthOrderNumber", businessReportDto.getThisMonthOrderNumber().toString());
        //今日到诊人数
        fill.put("todayVisitsNumber", businessReportDto.getTodayVisitsNumber().toString());
        //本周到诊人数
        fill.put("thisWeekVisitsNumber", businessReportDto.getThisWeekVisitsNumber().toString());
        //本月到诊人数
        fill.put("thisMonthVisitsNumber", businessReportDto.getThisMonthVisitsNumber().toString());

        String fileName = "运营数据统计表.xlsx";//创建文件名(改)
        String fileNameURL = null;
        try {
            fileNameURL = URLEncoder.encode(fileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setContentType("octets/stream");
        response.setHeader("Content-disposition", "attachment;filename=" + fileNameURL + ";" + "filename*=utf-8''" + fileNameURL);
        response.addHeader("Pargam", "no-cache");
        response.addHeader("Cache-Control", "no-cache");

        try {
            // 第一个参数，需要操作的sheet的索引
            // 第二个参数，需要复制的区域的第一行索引
            // 第三个参数，需要复制的区域的最后一行索引
            // 第四个参数，需要插入的位置的索引
            // 第五个参数，填充行区域中${}的值
            // 第六个参数，是否需要删除原来的区域
            // 需要注意的是，行的索引一般要减一
            excel.addRowByExist(0, 12, 12, 13, rows, true);
            // 第一个参数，需要操作的sheet的索引
            // 第二个参数，替换sheet当中${<变量的值>}的值
            excel.fillVariable(0, fill);
            try (OutputStream os = response.getOutputStream()) {
                os.write(excel.getBytes());
                os.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
